package org.example.cardgame.entity;

import lombok.Data;
import org.example.cardgame.utils.PokerComparator;

import java.util.*;

@Data
public class CardGroup {

    private List<Card> pokers;        //5张牌
    private CardType type;      //牌型
    private long power;  //牌的大小

    public CardGroup(List<Card> pokers) {
        assert pokers.size() == 5;
        this.pokers = pokers;
        Collections.sort(pokers, new PokerComparator());
        this.power = computePower();
    }

    /**
     * 为当前牌组计算power
     * @return
     */
    private long computePower() {
        //皇家同花顺
        if (isFlush() && isStraight()) {
            this.type = CardType.STRAIGHT_FLUSH;
            return (long)(9 * Math.pow(10, 10)) + this.computeCardPoint();
        }
        //同花顺
        /*if (!isFlush() && isStraight()) {
            this.type = CardType.STRAIGHT_FLUSH;
            return (long)(9 * Math.pow(10, 10)) + this.computeCardPoint();
        }*/
        /*//四条
        if (isSiTiao()) {
            this.type = CardType.FOUR_OF_A_KIND;
            return (long)(9 * Math.pow(10, 10)) + this.computeCardPoint();
        }

        //葫芦
        if (isFullHouse()) {
            this.type = CardType.FULL_HOUSE;
            return (long)(9 * Math.pow(10, 10)) + this.computeCardPoint();
        }*/

        //同花
        if (isFlush()) {
            this.type = CardType.FLUSH;
            return (long)(6 * Math.pow(10, 10)) + this.computeCardPoint();
        }
        //顺子
        if (isStraight()) {
            this.type = CardType.STRAIGHT;
            return (long)(5 * Math.pow(10, 10)) + this.computeCardPoint();
        }
        //其他牌型
        type = getOtherType();
        switch (type) {
            case FOUR_OF_A_KIND:
                //Math.pow(10, 10) 返回10的10次幂
                return (long)(8 * Math.pow(10, 10)) + this.computeCardPoint();
            case FULL_HOUSE:
                return (long)(7 * Math.pow(10, 10)) + this.computeCardPoint();
            case THREE_OF_A_KIND:
                return (long)(4 * Math.pow(10, 10)) + this.computeCardPoint();
            case TWO_PAIR:
                return (long)(3 * Math.pow(10, 10)) + this.computeCardPoint();
            case ONE_PAIR:
                return (long)(2 * Math.pow(10, 10)) + this.computeCardPoint();
            case HIGH_CARD:
                return (long)(1 * Math.pow(10, 10)) + this.computeCardPoint();
            default:
                break;
        }
        return 0;
    }

    /**
     * 判断5张牌是否为同花
     * @return
     */
    private boolean isFlush() {
        boolean flag = true;
        for (int i = 1; i < 5; i++) {
            if (pokers.get(i).getType() != pokers.get(i - 1).getType()) {
                flag = false;
                break;
            }
        }
        return flag;
    }
    /**
     * 判断5张牌是否为四条
     * @return
     */
    private boolean isSiTiao() {
        int count = 0;
        for (int i = 1; i < 5; i++) {
            if (pokers.get(i).getNumber() != pokers.get(i - 1).getNumber()) {
                count++;
            }
        }
        if (count > 1) {
            return false;
        }
        return true;
    }
    /**
     * 判断5张牌是否为葫芦
     * @return
     */
    private boolean isFullHouse() {
        int count = 0;
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < 5; i++) {
            if (!map.containsKey(pokers.get(i).getNumber())) {
                map.put(String.valueOf(pokers.get(i).getNumber()), String.valueOf(pokers.get(i).getNumber()));
            }
        }
        Set<String> strings = map.keySet();
        if (strings.size() > 2) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 判断5张牌是否为顺子
     * @return
     */
    private boolean isStraight() {
        try {
            boolean flag = true;
            for (int i = 1; i < 5; i++) {
                if (pokers.get(i).getNumber() != pokers.get(i - 1).getNumber() - 1) {
                    flag = false;
                    break;
                }
            }
            //5432A特殊情况
            if (pokers.get(4).getNumber() == 5 && pokers.get(3).getNumber() == 4 && pokers.get(2).getNumber() == 3 && pokers.get(1).getNumber() == 2 && pokers.get(0).getNumber() == 1 ) {
                flag = true;
            }
            return flag;
        } catch (Exception e) {
            return false;
        }
    }

    private long computeCardPoint() {
        long res = 0;
        for (Card p: pokers) {
            int number = p.getNumber();
            if (number == 1) {
                res = res * 100 + 14;
            } else if (number == 2) {
                res = res * 100 + 15;
            } else {
                res = res * 100 + number;
            }
        }
        return res;
    }

    /**
     * 判断5张牌为同花和顺子以外的其他具体牌型
     * @return
     */
    private CardType getOtherType() {
        int count = 0;
        for (int i = 0; i < 5; i++) {
            for (int j = i + 1; j < 5; j++) {
                if (pokers.get(j).getNumber() == pokers.get(i).getNumber()) {
                    count += 1;
                }
            }
        }
        if (count == 6) {
            changeCardPositionForFourKind();
            return CardType.FOUR_OF_A_KIND;
        } else if (count == 4) {
            changeCardPositionForFullHouse();
            return CardType.FULL_HOUSE;
        } else if (count == 3) {
            changeCardPositionForThreeKind();
            return CardType.THREE_OF_A_KIND;
        } else if (count == 2) {
            changeCardPositionForTwoPair();
            return CardType.TWO_PAIR;
        } else if (count == 1) {
            changeCardPositionForOnePair();
            return CardType.ONE_PAIR;
        }
        return CardType.HIGH_CARD;
    }

    /**
     * 为“四条“牌型修正牌的顺序
     */
    private void changeCardPositionForFourKind() {
        if (pokers.get(0).getNumber() != pokers.get(1).getNumber()) {
            Card tmpPoker = pokers.get(0);
            pokers.set(0, pokers.get(4));
            pokers.set(4, tmpPoker);
        }
    }

    /**
     * 为“葫芦“牌型修正牌的顺序
     */
    private void changeCardPositionForFullHouse() {
        if (pokers.get(1).getNumber() != pokers.get(2).getNumber()) {
            Card tmpPoker = pokers.get(0);
            pokers.set(0, pokers.get(3));
            pokers.set(3, tmpPoker);

            tmpPoker = pokers.get(1);
            pokers.set(1, pokers.get(4));
            pokers.set(4, tmpPoker);
        }
    }

    /**
     * 为“三条“牌型修正牌的顺序
     */
    private void changeCardPositionForThreeKind() {
        if (pokers.get(0).getNumber() != pokers.get(2).getNumber()) {
            Card tmpPoker = pokers.get(0);
            pokers.set(0, pokers.get(3));
            pokers.set(3, tmpPoker);
        }
        if (pokers.get(1).getNumber() != pokers.get(2).getNumber()) {
            Card tmpPoker = pokers.get(1);
            pokers.set(1, pokers.get(4));
            pokers.set(4, tmpPoker);
        }
    }

    /**
     * 为“两对“牌型修正牌的顺序
     */
    private void changeCardPositionForTwoPair() {
        if (pokers.get(0).getNumber() != pokers.get(1).getNumber()) {
            Card tmpPoker = pokers.get(0);
            pokers.set(0, pokers.get(2));
            pokers.set(2, tmpPoker);
        }
        if (pokers.get(2).getNumber() != pokers.get(3).getNumber()) {
            Card tmpPoker = pokers.get(2);
            pokers.set(2, pokers.get(4));
            pokers.set(4, tmpPoker);
        }
    }

    /**
     * 为“一对“牌型修正牌的顺序
     */
    private void changeCardPositionForOnePair() {
        int c = 0;
        for (c = 0; c < 4; c++) {
            if (pokers.get(c).getNumber() == pokers.get(c + 1).getNumber()) {
                break;
            }
        }
        Card tp1 = pokers.get(c);
        Card tp2 = pokers.get(c + 1);
        for (int i = c - 1; i >= 0; i--) {
            pokers.set(i + 2, pokers.get(i));
        }
        pokers.set(0, tp1);
        pokers.set(1, tp2);
    }
}
